#!/usr/bin/python
# -*- coding: utf-8 -*-

import Queue, serial, sys, socket 
import logging, logging.handlers, logging.config, threading

from server import server
from lectorGen import lector
from configurador import Configurador

def loadDriver(classname):
    ''' returns a class of "classname" from module "modname". '''
    module = __import__("drivers."+classname)
    classobj = getattr(module, classname)
    return classobj

class srvLector:
    
    # Constructor 
    
    def __init__(self):
        self.my_logger = logging.getLogger('lector.srv')
        self.acabar = False
	self.device = {}
	self.lectors = {}
        self.q = Queue.Queue(0)

        self.my_logger.info("*** Lector de dades v.3.0 ***************************************")

        # Llegim la configuracio del fitxer config.xml

        self.my_logger.info("Carregant el fitxer de configuracio...")
        self.conf = Configurador()
        if not self.conf.llegeix():
           self.my_logger.error("Error al carregar la configuracio!")
           raise Exception, "Error al carregar la configuracio"  

        # Inicialitzam els dispositius i instanciam els lectors

	self.my_logger.info("Inicialitzant dispositius ...")
        self.__initDevices__()
        self.my_logger.info("Carregant drivers i instanciam els lectors ...")
        self.__initLectors__()

        # Instanciam el servidor de connexions TCP/IP
       
        self.my_logger.info("Instanciant servidor TCP/IP ...")
 
        try: 
            srv = server(self.q, self.my_logger)
            srv.setDaemon(True)
            srv.start()
        except IOError, err:
            self.my_logger.error(str(err))
            raise IOError, str(err)

    def __initDevices__(self):
        for id, confDev in self.conf.devices.iteritems():
            if confDev["type"] == "serial":
               config = confDev["config"]
               try:
                   self.device[id] = (serial.Serial(config["port"], config["baud"], timeout=float(config["timeout"]), bytesize=int(config["bits"])),
                                      threading.Semaphore())
               except serial.serialutil.SerialException, err:
                   raise serial.serialutil.SerialException, "Error initializing device %s: %s" % ( id, str(err) )
 
    def __initLectors__(self):
        for id, confEquip in self.conf.equips.iteritems():
            self.my_logger.info("\tCarregant driver analitzador %s ..." % id)
            equip = self.loadDriver(id, confEquip)
            self.lectors[id] = self.initLector(equip, confEquip);

    """
       Metode que empram per carregar els drivers
    """

    def loadDriver(self, id, pConfig):
        config = pConfig["config"]
        requests = pConfig["requests"]
        params = config["params"]

        equipCommC = loadDriver(config["driver"])
        device = self.device.get(config["device"])
       
        if not device:
           raise Exception, "El dispositiu asociat no s'ha definit be"  
	try:
            equipComm = equipCommC(id, device)
        except Exception, err:
            self.my_logger.error(str(err))
            raise Exception, str(err)
	else:
            equipDadesC = loadDriver(config["dataDriver"])
            equipDades = equipDadesC(equipComm, requests, params["model"])
            
        equipComm.logger = logging.getLogger('lector.comm') 
        equipDades.logger = self.my_logger
        
        return equipDades

    """
       Metode que ens instancia un thread per lector
    """

    def initLector(self, equip, pConfig):
        config = pConfig["config"]
        params = config["params"]
        Tgravacio = int(params["tempsgravacio"])
        Tlectura = int(params["tempslectura"])

        # Instanciam el servidor de lectures
 	try:
            myLector = lector(equip)
        except Exception, e:
            self.my_logger.error(str(e))
            raise Exception, str(e)
           
        myLector.setMaxLectures(Tgravacio, Tlectura)
        myLector.setDaemon(True)

        self.my_logger.info("*****************************************************************")
        self.my_logger.info("    Analitzador = "+params["fabricant"]+" model "+params["model"])
        self.my_logger.info("    Interval de lectura  = "+params["tempslectura"]+" segons")
        self.my_logger.info("    Interval de gravacio = "+params["tempsgravacio"]+" minuts")
        self.my_logger.info("*****************************************************************")
         
        return myLector 

    """
        Metodes referents a cada comanda valida del servidor
    """
    
    def reloadConf(self, id=None):
   
        self.my_logger.info("Reloading config file ...")
        if not self.conf.llegeix():
           return 'SRV_CONF_ERR'

        for id, confEquip in self.conf.equips.iteritems():
            parmAnalitza = confEquip["config"]["params"]
            try:     
                lector = self.lectors.get(id)
            except Exception, e:
                return "SRV_ERR: %s" % str(e)
            else:
                lector.setMaxLectures(int(parmAnalitza["tempsgravacio"]), int(parmAnalitza["tempslectura"]))
                lector.equip.setVariables(confEquip["requests"])
                return "RELOAD\tOK"
        return ''

    def start(self, id):
        lector = self.lectors.get(id)
        if not lector.isAlive():
           lector.start()
           return("START\tOK")

        return("ALLREADY START") 

        
    def startAll(self, id=None):
        for lector in self.lectors.values():
	    lector.start()

        return("STARTING")       

    def shutdown(self, id=None):
        self.acabar = True
        return("DONE")

    def getID(self, id):
        self.my_logger.debug("Agafant el lector %s" % id)
        lector = self.lectors.get(id)
        self.my_logger.debug("Llegint idEquip ...")
        if lector and lector.ready:
	   return(lector.idEquip)
        
        return ("INT_ERR")

    def getVars(self, id):
        lector = self.lectors.get(id)
        return (lector.equip)

    def forceReq(self, id):
        lector = self.lectors.get(id)	
	lector.forceReq = True
        return("FORCE REQUESTED")

    def readConf(self, id):
        return(self.conf)

    def status(self, id):
        lector = self.lectors.get(id)
        
	msgComm = "NOCOMM" if lector.errorComm else "COMM\t%s" % lector.equip.lastError
        msgStatus = "STARTED" if lector.isAlive() else "STOPPED"
        msgStatus = "PAUSED" if lector.isAlive() and lector.pause else msgStatus

        return("%s\t%s" % (msgStatus, msgComm))

    def getDefs(self, id):
        lector = self.lectors.get(id)
        return(lector.equip.getDefs())

    def identify(self, id):
        lector = self.lectors.get(id)
        lector.identifyEquip()
        if lector.idEquip:
           return(lector.idEquip)

        return("IDENT ERROR")      
            
    def pause(self, id):
        lector = self.lectors.get(id)
        if lector.isAlive():
           lector.pause = True 
           return("PAUSED") 

        return("IS STOPPED")

    def resume(self, id):
        lector = self.lectors.get(id)
        if lector.isAlive():
           lector.pause = False 
           return("RESUMED") 

        return("IS STOPPED")

    def donothing(self, id):
        pass

    def errorCmd(self, id):
        return("NOT IMPLEMENTED")

    # Accions valides del servidor
    
    validActions = {"GETID"   : getID,
                    "GETVARS" : getVars,
                    "GETCONF" : readConf,
                    "GETDEFS" : getDefs,
                    "IDENT"   : identify,
                    "FORCEREQ": forceReq,
                    "SHUTDOWN": shutdown,
                    "START"   : start,
                    "STARTALL": startAll,
                    "PAUSE"   : pause,
                    "RESUME"  : resume,
                    "RELOAD"  : reloadConf,
                    "STATUS"  : status,
                    "QUIT"    : donothing,
                    "HELP"    : donothing}
    
    # Metode que cridarem cada vegada que volem processar una comanda rebuda
    
    def dispatchMessages(self):
        ((cmd, args), sockCli) = self.q.get(block=True)
        try:
            id = int(args) if args else 0
            retval = self.validActions.get(cmd, self.errorCmd)(self, id)
            if retval:
               sockCli.send("%s\r" % retval)
            self.q.task_done()
        except socket.error, e:
               self.my_logger.error("Enviant resposta: %s" % str(e))
        except KeyboardInterrupt, e:
            self.acabar = True
	    return
	except Exception, e:
            self.my_logger.error(str(e))
            try:
               sockCli.send("SRV_ERR:\t%s\r" % str(e))
            except socket.error, e:
               self.my_logger.error(str(e)) 
        
